// shell_func.c
//
//		implement some built in function
#include "shell.h"
#include "shell_func.h"
#include "../lib/lib.h"
#include "syscall.h"

struct command builtin_set[] = { 
            { "help", help },     { "quit", quit },    { "echo", echo }, 
            { "cd", cd },         { "pwd", pwd },      { "ls", ls },     
            { "mkdir", mkdir },   { "rmdir", rmdir },  { "rename", rename },
	        { "rm", rm },	      { "cp", cp },		   { "append", append },
            { "cat", cat },       { "get", get },      { "new", new }
};


struct variable env_variables_set[] = {
		{ "PATH", "/bin" },
		{ "SHELL", "/bin/sbash" },
		{ "USER", "NachOS" },
		{ "PWD", "/home/NachOS" },
		{ "HOME", "/home" }
};

char szHelpMessage[][64] = {
        "help    show help message.",
        "quit    exit the shell.",
        "echo    print variable on console.",
        "cd      change current working directory.",
        "pwd     show current working directory.", 
        "ls      list files in the directory.",
        "mkdir   make new directories.",
        "rmdir   remove existed directories.",
        "rename  rename a file or directory.",
        "rm      remove existed files.",
        "cp      copy a existed file.",
        "append  append a existed file to another.",
        "cat     show the content of text files.",
        "get     get a new file from the linux file system.",
        "new     create a new file."
};

void usage()
{
    int i = 0;
    int size = sizeof(szHelpMessage)/sizeof( szHelpMessage[0] );
    for( i = 0; i < size; i++ ) {
        sb_printf( szHelpMessage[i] );
        sb_printf( "\n" );
    }
}

// command process
int readCommand(char *cmd) {
	int i = 0;
    char szFilePath[64];
    GetCwd( szFilePath, 64);
    sb_printf( szFilePath );
    sb_printf( "$ " );

	do {

		Read(&cmd[i], 1, ConsoleInputId);

	} while (cmd[i++] != '\n');

	cmd[--i] = '\0';

	return sb_strlen(cmd);
}

int parseCommand(char *cmd) {

	int i;
	int len;
	int argc;
	char *argv[MAX_ARG_NUM];

	argc = 0;
	len = sb_strlen(cmd);

	for (i = 0; i < len; i++) {
		for (; sb_isspace(cmd[i]); i++) { // skip space
		}

		if (i < len) {
			argv[argc++] = &cmd[i];
		}

		for (; !sb_isspace(cmd[i]) && i < len; i++) { // skip argv
		}
		// make every argv end with '\0'
		cmd[i] = '\0';
	}

	if (!argc) {
		return -1;
	}

	for (i = 0; i < sizeof(builtin_set) / sizeof(struct command); i++) {

		if (!sb_strcmp(argv[0], builtin_set[i].cmdName)) {
			// execute built in commands
			builtin_set[i].builtInFun(argc, argv);
			return 0;
		}
	}

	// command only contains space : ' ' '\n' '\t' etc.
	if (!(sb_strlen(argv[0]) == 1)) {
		sb_printf(argv[0]);
		sb_printf(" : Command Not Found!\n");
	}

	return 0;
}

// built in functions
void cd(int argc, char **argv) {
    int ret;
    if( argc < 2 ) {
        sb_strcp("/", argv[1]);
    }
    
    ret = ChDir( argv[1] );
    if ( 0!= ret )
        sb_printf( "Path not found.\n" );
	return;
}

void pwd(int argc, char **argv) {
    char szFilePath[64];
    GetCwd( szFilePath, 64);
    sb_printf( szFilePath );
    sb_printf( "\n" );
	return;
}

void echo(int argc, char **argv) {
	int i, j;

	for (i = 1; i < argc; i++) {
		if (*argv[i] == '$') {
			char *variable = argv[i] + 1;
			for (j = 0; j < sizeof(env_variables_set) / sizeof(struct variable); j++) {
				if (!sb_strcmp(variable, env_variables_set[j].varName)) {
					sb_printf(env_variables_set[j].varValue);
					sb_printf("\n");
					break;
				}
			}
			continue;
		}
		sb_printf(argv[i]);
		sb_printf("\n");
	}

	return;
}

void help(int argc, char **argv) {
    if( argc == 2 && !sb_strcmp( argv[1], "myself" )) {
        usage();
        return;
    }
	sb_printf("God helps one who helps himself\n");
	return;
}

void quit(int argc, char **argv) {
	// let me out of here!
	wantExitShell = 1;

	return;
}

void mkdir(int argc, char **argv) {
    int i, ret = 0;
    if ( argc < 2 ) { 
        sb_printf( "usage: mkdir DIRECTORY...\n" );
        return;
    }
    for ( i = 1; i < argc; i++ ) {
        ret = MkDir( argv[i] );
        if( 0 != ret ) {
            sb_printf( argv[i] );
            sb_printf( ": directory existed already.\n" );
        }
    }
    return;
}

void rmdir(int argc, char **argv) {
    int i, ret = 0, resv = 0;
    if ( argc < 2) {
        sb_printf( "usage: rmdir [option...] DIRECTORY...\n" );
        return;
    }

    for ( i = 1; i < argc; i++ ) {
        if( sb_strcmp( argv[i], "-r" ) == 0 ) {
            resv = 1;
            continue;
        }
        
        ret = RmDir( argv[i], resv );
        if( -1 == ret ) {
            sb_printf( argv[i] );
            sb_printf( ": no such directory.\n" );
        }
        else if( -2 == ret) {
            sb_printf( argv[i] );
            sb_printf( ": not a directory.\n" );
        }
        else if( -4 == ret ) {
            sb_printf( argv[i] );
            sb_printf( ": directory not empty.\n" );
        }
    }

    return;
}

void rename(int argc, char **argv) {
    int ret; 
    if ( argc != 3 ) {
        sb_printf( "Usage: rename filename new_filename\n" );
        return;
    }
    
	ret = Rename( argv[1], argv[2]);
	if( 0 != ret )
		sb_printf( "No such file or directory.\n" );
	return;
}

void rm(int argc, char **argv) {
    int i, ret = 0;
    if ( argc < 2) {
        sb_printf( "usage: rm FILE...\n" );
        return;
    }

    for ( i = 1; i < argc; i++ ) {
        ret = Remove( argv[i] );
        if( -1 == ret ) {
            sb_printf( argv[i] );
            sb_printf( ": no such file.\n" );
        }
        else if( -3 == ret ) {
            sb_printf( argv[i] );
            sb_printf( ": is a directory.\n" );
        }
    }

    return;
}

void cp(int argc, char** argv) {
    int ret;
    if( argc != 3 ) {
        sb_printf( "Usage: cp src_file dest_file\n" );
        return;
    }
    
	ret = Copy( argv[1], argv[2] );
	if( 0 != ret )
		sb_printf( "copy file failed.\n" );
	return;
}

void append(int argc, char** argv) {
	int ret;
    if( argc != 3 ) {
        sb_printf( "Usage: append src_file dest_file\n" );
        return;
    }

    ret = Append( argv[1], argv[2] );
	if( 0 != ret )
		sb_printf( "Append file failed.\n" );
	return;
}

void ls(int argc, char **argv) {
    
    int count = 10, ret = 0, i = 0, resv = 0, list = 0;
    char path[64];
    char * pPath = path;
    struct dirEnt dirents[10];

    path[0] = '\0';
    while( ++i < argc ) {
        if( 0 == sb_strcmp( argv[i], "-l" ))
            list = 1;
        else if ( 0 == sb_strcmp( argv[i], "-R" ))
            resv = 1;
        else 
            sb_strcp(argv[i], pPath);
    }
   
    if( 0 == sb_strcmp( "", pPath ) )
        pPath = "."; 

    if( resv ) {
        ListDir( pPath, resv );
        return;
    }
    
    ret = GetDentry( pPath, dirents, &count);
    if( 0 != ret ){
        sb_printf( "Invalid path.\n" );
        return;
    }
    if( !count )
        return;

    if( !list ) {
        for( i = 0; i< count; i++ ) {
            sb_printf( dirents[i].entryName );
            if( dirents[i].isDir ) 
                sb_printf( "/" );
            sb_printf( "\t" );
        }
        sb_printf( "\n" );
    } else  {
        for ( i = 0; i < count; i++ ) {
            PrintNum( dirents[i].linkCnt );
            sb_printf( "\t" );
            sb_printf( dirents[i].isDir? "Dir ": "File" );
            sb_printf( "\t" );
            sb_printf( dirents[i].entryName );
            sb_printf( "\n" );
        }
    }
    
    return;
}

void cat(int argc, char** argv) {
    int i, ret = 0;
    if ( argc < 2 ) { 
        sb_printf( "usage: cat FILE...\n" );
        return;
    }
    
    for ( i = 1; i < argc; i++ ) {
        ret = Cat( argv[i] );
        if( 0 != ret ) {
            sb_printf( argv[i] );
            sb_printf( ": no such file.\n" );
        }
    }
    return;
}

void get(int argc, char** argv) {
	int ret;
    if( argc != 3 ) {
        sb_printf( "Usage: get linux_file dest_file\n" );
        return;
    }
    
    ret = GetFile( argv[1], argv[2] );
    if( 0 != ret )
		sb_printf( "Unable to get a file from linux file system.\n" );

    return;
}

void new(int argc, char **argv) {
    int i, ret = 0;
    if ( argc < 2 ) { 
        sb_printf( "usage: new FILE...\n" );
        return;
    }
    for ( i = 1; i < argc; i++ ) {
        ret = Create( argv[i] );
        if( 0 != ret ) {
            sb_printf( argv[i] );
            sb_printf( ": file existed already.\n" );
        }
    }
    return;
}


